#include "HashTable.h"

Entry *hashTable[HASH_SIZE]={NULL};

Entry *blkStack[STACK_SIZE];
int top = 0; //global
//blkStack[top] is field varible list

void init()
{
	Function read=malloc(sizeof(struct Function_));
	read->name=malloc(16);
	strcpy(read->name,"read");
	read->isDefined=1;
	read->line=0;

	read->r_type=malloc(sizeof(struct Type_));
	read->r_type->kind=BASIC;
	read->r_type->basic=TYPE_INT;
	read->param=NULL;
	funcChk_Inst(read);


	Function write=malloc(sizeof(struct Function_));
	write->name=malloc(16);
	strcpy(write->name,"write");
	write->isDefined=1;
	write->line=0;

	write->r_type=malloc(sizeof(struct Type_));
	write->r_type->kind=BASIC;
	write->r_type->basic=TYPE_INT;
	write->param=malloc(sizeof(struct FieldList_));
	write->param->name = malloc(16);
	strcpy(write->param->name,"write_param");
	write->param->type=malloc(sizeof(struct Type_));
	write->param->type->kind = BASIC;
	write->param->type->basic = TYPE_INT;
	write->param->tail=NULL;
	funcChk_Inst(write);
}

unsigned int hashPJW(char *name)
{
	unsigned int val = 0, i;
	for (; *name; ++name)
	{
		val = (val << 2) + *name;
		if (i = val & ~0x3fff)
			val = (val ^ (i >> 12)) & 0x3fff;
	}
	return val;
}

void varInsertTable(FieldList value)
{
	assert(value);

	unsigned int hashValue = hashPJW(value->name) % HASH_SIZE;

	Entry *curEntry = (Entry *)malloc(sizeof(Entry));
	curEntry->type = value->type;
	curEntry->name = value->name;
	curEntry->scope = top;

	curEntry->next = hashTable[hashValue];
	hashTable[hashValue] = curEntry;

	curEntry->blkNext = blkStack[top];
	blkStack[top] = curEntry;
}

void structInsertTable(Structure structure)
{
	assert(structure);

	unsigned int hashValue = hashPJW(structure->name) % HASH_SIZE;

	Entry *curEntry = (Entry *)malloc(sizeof(Entry));
	curEntry->type = (Type)malloc(sizeof(struct Type_));
	curEntry->type->kind = STRUCTURE;
	curEntry->type->structure = structure;
	curEntry->name = structure->name;
	curEntry->scope = top;

	curEntry->next = hashTable[hashValue];
	hashTable[hashValue] = curEntry;

	curEntry->blkNext = blkStack[top];
	blkStack[top] = curEntry;
}

int varInsertCheck(FieldList var)
{
	assert(var);

	unsigned int hashValue = hashPJW(var->name) % HASH_SIZE;

	for (Entry *tmp = hashTable[hashValue]; tmp && tmp->scope == top; tmp = tmp->next)
	{
		if (tmp->type->kind != FUNCTION && strcmp(tmp->name, var->name) == 0)
			return FALSE;
	}

	return TRUE;
}

int funcChk_Inst(Function func)
{
	assert(hashTable);

	unsigned int hashValue = hashPJW(func->name) % HASH_SIZE;

	//first check, note that no nested func exists, so scope is not considered
	for (Entry *tmp = hashTable[hashValue]; tmp != NULL; tmp = tmp->next)
	{
		if (tmp->type->kind != FUNCTION)
			continue;
		if (strcmp(func->name, func->name) != 0)
			continue;

		//find this name and it is a function   so redefined
		return FALSE;
	}

	//not exist before, then insert
	Entry *curEntry = (Entry *)malloc(sizeof(Entry));

	curEntry->type = (Type)malloc(sizeof(struct Type_));
	curEntry->type->kind = FUNCTION;
	curEntry->type->function = func;
	curEntry->name = func->name;

	curEntry->next = hashTable[hashValue];
	hashTable[hashValue] = curEntry;

	//check if there is redefined viriable here
	FieldList param = func->param; //a pointer

	while (param != NULL)
	{
		bool flag = varInsertCheck(param);
		if (flag == FALSE)
		{
			printf("Error type 3 at Line %d: Redefine variable \"%s\"\n", func->line, param->name);
			semantic_error++;
		}
		else
		{
			varInsertTable(param);
		}
		param = param->tail;
	}

	return TRUE;
}

int structInsertCheck(Structure structure)
{
	assert(structure);
	assert(hashTable);

	unsigned int hashValue = hashPJW(structure->name) % HASH_SIZE;
	Entry *tmp = hashTable[hashValue];
	for (; tmp != NULL && tmp->scope == top; tmp = tmp->next)
	{
		if (tmp->type->kind != FUNCTION && strcmp(tmp->name, structure->name) == 0)
			return FALSE;
	}
	return TRUE;
}

Type getTable(char *name)
{
	assert(name);
	assert(hashTable);

	unsigned int hashValue = hashPJW(name) % HASH_SIZE;

	Entry *tmp = hashTable[hashValue];
	for (; tmp != NULL; tmp = tmp->next)
		if (strcmp(tmp->name, name) == 0)
			return tmp->type;

	// Error: No such name
	return NULL;
}

void StkPush()
{
	top++;
}

void StkPop()
{
	for (Entry *p = blkStack[top]; p;) // p to be deleted
	{
		//del by row 如果双向链表 带头指针 前前后后指一指就可以轻松删掉了 不用这么麻烦
		unsigned int hashValue = hashPJW(p->name) % HASH_SIZE;
		if (hashTable[hashValue] == p)
			hashTable[hashValue] = p->next;
		else
		{
			Entry *q = hashTable[hashValue];
			for (; q->next != p; q = q->next)
				;
			q->next = p->next;
		}

		//del by col
		blkStack[top] = p->blkNext;

		//assert(p->type);
		//free(p->type); //only has to free those malloced before  		 cause segment fault   fix some but too troublesome
		//p->type = NULL;//没有用了 p马上也要被释放掉   之前在另一个结构体里已经把指针值赋过去了  几个指针指向的是同一块地方
		free(p);
		p = blkStack[top];
	}

	top--;
}